package com.lighting.common.feign.search.dto;

import com.lighting.common.feign.search.constant.QueryType;
import com.lighting.common.feign.search.dto.inside.BaseDto;
import com.lighting.common.feign.search.dto.inside.Condition;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;

import java.util.*;

@Getter
@Setter
public class Query extends BaseDto {

    @ApiModelProperty("指定返回的列，默认返回全部列")
    private String[] fields;

    @ApiModelProperty("查询条件")
    private List<Condition> conditionList = new ArrayList<>();

    @ApiModelProperty("高亮搜索结果的列")
    private Set<String> highlightFields = new HashSet<>();

    private List<String[]> sortList = new ArrayList<>();

    public Query(String indexName) {
        super(indexName);
    }

    public Query() {
    }

    public Query participle(String fieldName, Object value, String... fieldNames) {
        Condition query = new Condition(fieldName, value, QueryType.participle.name());
        query.setFieldNames(fieldNames);
        this.conditionList.add(query);
        return this;
    }

    public Query participle(String fieldName, Object value, Float boost, String... fieldNames) {
        Condition query = new Condition(fieldName, value, QueryType.participle.name());
        query.setBoost(boost);
        query.setFieldNames(fieldNames);
        this.conditionList.add(query);
        return this;
    }

    public Query eq(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.eq.name());
        this.conditionList.add(query);
        return this;
    }

    public Query ne(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.ne.name());
        this.conditionList.add(query);
        return this;
    }

    public Query gt(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.gt.name());
        this.conditionList.add(query);
        return this;
    }

    public Query gte(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.gte.name());
        this.conditionList.add(query);
        return this;
    }

    public Query lt(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.lt.name());
        this.conditionList.add(query);
        return this;
    }

    public Query lte(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.lte.name());
        this.conditionList.add(query);
        return this;
    }

    public Query geLe(String fieldName, Object v1, Object v2, String format) {
        Condition query = new Condition(fieldName, v1, v2, QueryType.geLe.name(), format);
        this.conditionList.add(query);
        return this;
    }

    public Query likeLeft(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.likeLeft.name());
        this.conditionList.add(query);
        return this;
    }

    public Query likeRight(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.likeRight.name());
        this.conditionList.add(query);
        return this;
    }

    public Query like(String fieldName, Object value) {
        Condition query = new Condition(fieldName, value, QueryType.like.name());
        this.conditionList.add(query);
        return this;
    }

    public Query in(String fieldName, List<Object> value) {
        Condition query = new Condition(fieldName, value, QueryType.in.name());
        this.conditionList.add(query);
        return this;
    }

    public Query notIn(String fieldName, List<Object> value) {
        Condition query = new Condition(fieldName, value, QueryType.notIn.name());
        this.conditionList.add(query);
        return this;
    }

    public Query exists(String fieldName) {
        Condition query = new Condition(fieldName, null, QueryType.exists.name());
        this.conditionList.add(query);
        return this;
    }

    public Query notExists(String fieldName) {
        Condition query = new Condition(fieldName, null, QueryType.noExists.name());
        this.conditionList.add(query);
        return this;
    }

    public Query or() {
        Condition condition = new Condition(null, null, QueryType.or.name());
        this.conditionList.add(condition);
        return this;
    }

    public Query and(Query query) {
        List<List<Condition>> list = new ArrayList<>();
        List<Condition> conditions = new ArrayList<>();
        for (Condition condition : query.getConditionList()) {
            if (QueryType.or.name().equals(condition.getQueryType())) {
                if (!conditions.isEmpty()) {
                    list.add(conditions);
                }
                conditions = new ArrayList<>();
                continue;
            }
            conditions.add(condition);
        }
        if (!conditions.isEmpty()) {
            list.add(conditions);
        }
        if (list.isEmpty()) {
            return this;
        }
        if (list.size() == 1) {
            Condition condition = new Condition(null, null, QueryType.and.name());
            condition.getConditionList().addAll(query.getConditionList());
            this.conditionList.add(condition);
            return this;
        }
        Condition condition = new Condition(null, null, QueryType.or.name());
        for (List<Condition> conditionList : list) {
            Condition c = new Condition(null, null, QueryType.and.name());
            c.getConditionList().addAll(conditionList);
            condition.getConditionList().add(c);
        }
        this.conditionList.add(condition);
        return this;
    }

    public Query highlight(String... columns) {
        this.highlightFields.addAll(Arrays.asList(columns));
        return this;
    }

    public Query orderByAsc(String column) {
        this.sortList.add(new String[]{"asc", column});
        return this;
    }

    public Query orderByDesc(String column) {
        this.sortList.add(new String[]{"desc", column});
        return this;
    }
}
